package com.hitqz.robot.dispatch.netty.thread;

/**
 * 光电模块读取信息
 * @author xupkun
 * @date 2025/3/6
 */

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.StrUtil;
import com.hitqz.robot.api.business.entity.SensorModulesEntity;
import com.hitqz.robot.dispatch.netty.model.IOReadModulesDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static ch.qos.logback.core.encoder.ByteArrayUtil.hexStringToByteArray;

@Slf4j
public class IOModulesReadBatch implements Runnable {
    private static final Pattern IP_PATTERN = Pattern.compile("^(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}):(\\d+)$");
    private static final int SOCKET_TIMEOUT_MS = 3000;
    private static final int RETRY_DELAY_SECONDS = 5;
    // 4通道
    //private static final byte[] DATA_TO_SEND = hexStringToByteArray("FE02000000046DC6");
    private static final byte[] DATA_TO_SEND = hexStringToByteArray("FE02000000106DC9");
    // FE02
    private static final long COOL_DOWN_PERIOD_MS = 5000; // 5秒冷却时间

    // FE 02 00 00 00 04 6D C6
    // FE 02 00 00 00 10 6D C9
    private final IOReadModulesDto sensorModulesEntity;
    private final ConcurrentHashMap<Integer, Integer> lastStatus = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<Integer, Long> lastTriggerTime = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<Integer, Long> keepTime = new ConcurrentHashMap<>();;


    public IOModulesReadBatch(IOReadModulesDto sensorModulesEntity) {
        this.sensorModulesEntity = sensorModulesEntity;
    }

    @Override
    public void run() {
        String ip = sensorModulesEntity.getIp();
        Matcher matcher = IP_PATTERN.matcher(ip);
        if (!matcher.matches()) {
            throw new IllegalArgumentException("Invalid IP address format: " + ip);
        }
        String ipAddress = matcher.group(1);
        int port = Integer.parseInt(matcher.group(2));
        try {
            if (NetUtil.ping(ipAddress, SOCKET_TIMEOUT_MS)) {
                try (Socket socket = new Socket()) {
                    socket.connect(new InetSocketAddress(ipAddress, port), SOCKET_TIMEOUT_MS);
                    try (OutputStream outputStream = socket.getOutputStream();
                         InputStream inputStream = socket.getInputStream()) {
                        while (!Thread.currentThread().isInterrupted()) {
                            outputStream.write(DATA_TO_SEND);
                            outputStream.flush();
                            byte[] buffer = new byte[1024];
                            int bytesRead = inputStream.read(buffer);
                            if (bytesRead > 0) {
                                byte[] receivedData = Arrays.copyOf(buffer, bytesRead);
                                // 低位
                                int lowStatus = receivedData[3] & 0xff;
                                String lowResult = String.format("%4s",
                                                StrUtil.padPre(Integer.toBinaryString(lowStatus),
                                                        8, "0"))
                                        .replace(" ", "0")
                                        .replace("0", "-0-")
                                        .replace("1", "-1-");
                                lowResult = StrUtil.reverse(lowResult);
                                // 高位
                                int heightStatus = receivedData[4] & 0xff;
                                String heightResult = String.format("%4s",
                                                StrUtil.padPre(Integer.toBinaryString(heightStatus),
                                                        8, "0"))
                                        .replace(" ", "0")
                                        .replace("0", "-0-")
                                        .replace("1", "-1-");
                                heightResult = StrUtil.reverse(heightResult);
                                String allResult = lowResult + heightResult;
                                List<String> finalList = Arrays.stream(allResult.split("-"))
                                        .filter(StrUtil::isNotEmpty)
                                        .collect(Collectors.toList());
                                processStatus(finalList, ipAddress);
                            }
                        }
                    }
                }
            } else {
                throw new IllegalStateException("地址无法连接: " + ipAddress);
            }
        } catch (IOException | NumberFormatException e) {
            log.error("发生IO异常或端口解析错误: {}", e.getMessage());
            retryAfterDelay();
        } catch (Exception e) {
            //log.error("发生未知异常: {}", e.getMessage());
            retryAfterDelay();
        }
    }

    private void processStatus(List<String> finalList, String ipAddress) {
        long currentTime = System.currentTimeMillis();
        for (int i = 0; i < finalList.size(); i++) {
            String current = finalList.get(i);
            Integer currentLastStatus = lastStatus.get(i);
            String uri = "";
            int finalI = i;
            Optional<SensorModulesEntity> optional = sensorModulesEntity.getIoModulesReadList()
                    .stream().filter(t->t.getPointSn()== finalI).findFirst();
            if (optional.isPresent()) {
                SensorModulesEntity sensorModulesEntity = optional.get();
                if (currentLastStatus != null) {
                    if (currentLastStatus == 0 && "1".equals(current)) {
                        uri = StrUtil.isNotBlank(sensorModulesEntity.getUpUri()) ? sensorModulesEntity.getUpUri() : "";
                        lastTriggerTime.put(i, currentTime);
                        log.info("{}---由0变成1---{}", ipAddress, sensorModulesEntity.getPointSn());
                        keepTime.put(i, 0L);
                    } else if (currentLastStatus == 1 && "0".equals(current)) {
                        uri = StrUtil.isNotBlank(sensorModulesEntity.getDownUri()) ? sensorModulesEntity.getDownUri() : "";
                        lastTriggerTime.put(i, currentTime);
                        log.info("{}---由1变成0---{}", ipAddress, sensorModulesEntity.getPointSn());
                        keepTime.put(i, 0L);
                    } else if (currentLastStatus.equals(Integer.parseInt(current))) {
                        if (lastTriggerTime.get(i) != null) {
                            keepTime.put(i, currentTime - lastTriggerTime.get(i));
                            uri = "0".equals(current) ? sensorModulesEntity.getDownUri() : sensorModulesEntity.getUpUri();
                        }
                    }
                } else {
                    if (sensorModulesEntity.getSensorAction() == 0) {
                        uri = "0".equals(current) ? sensorModulesEntity.getDownUri() : sensorModulesEntity.getUpUri();
                    }
                }
                lastStatus.put(i, Integer.parseInt(current));
                dispatchAction(uri, i, currentTime, currentLastStatus, sensorModulesEntity);
            }
        }
    }


    private void retryAfterDelay() {
        try {
            TimeUnit.SECONDS.sleep(RETRY_DELAY_SECONDS);
            Thread thread = new Thread(new IOModulesReadBatch(sensorModulesEntity));
            thread.start();
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(ex);
        }
    }

    private void dispatchAction(String uri, int pointSn, long currentTime, Integer value, SensorModulesEntity sensorModulesEntity) {
        if (StrUtil.isEmpty(uri)) {
            return;
        }
        if (lastStatus.get(pointSn) != null && value != null) {
            if (sensorModulesEntity.getSensorKeep() > 0) {
                if (keepTime.get(sensorModulesEntity.getPointSn()) < (sensorModulesEntity.getSensorKeep() * 1000)) {
                    return;
                }
            }
        }
        lastTriggerTime.remove(pointSn);
        switch (sensorModulesEntity.getSensorAction()) {
            case 0 -> {
                try {
                    RestTemplate restTemplate = new RestTemplate();
                    String[] uris = uri.split(",");
                    for (String url: uris) {
                        String result = restTemplate.postForObject(url, "", String.class);
                        log.info("请求地址{}-结果-{}", url, result);
                    }
                } catch (Exception e) {
                    log.error("发送请求发生异常: {}", e.getMessage());
                }
                // 更新上次请求时间
                //lastRequestTime.put(pointSn, currentTime);
                break;
            }
            case 1 -> {
                try {
                    RestTemplate restTemplate = new RestTemplate();
                    String result = restTemplate.postForObject(uri, "", String.class);
                    log.info("任务请求地址{}-结果-{}", uri, result);
                } catch (Exception e) {
                    log.error("发送请求发生异常: {}", e.getMessage());
                }
                //lastRequestTime.put(pointSn, currentTime);
                break;
            }
            default -> {
                break;
            }

        }
    }
}
